﻿using System;
using System.Threading;

namespace EastForceCondensor.CommCtrl
{
    public struct VoltageInfo
    {
        public uint timestamp;
        public double voltage;
    }
    public struct ADDataSet
    {
        public long timestamp;
        public float[] voltageArray;
        public float batteryVolt;
        public ADDataSet(long _timestamp, float[] _voltageArray, float _batteryVolt)
        {
            timestamp = _timestamp;
            voltageArray = _voltageArray;
            batteryVolt = _batteryVolt;
        }
    }
    public enum CMD { START, STOP, GAIN };
    public enum CMD_RES
    {
        START_OK, START_FAIL,
        STOP_OK, STOP_FAIL,
        GAIN_OK, GAIN_FAIL,
        EXCEPTION
    };

    public class CommMgmt
    {
        private UdpMgmt udpManager1 = new UdpMgmt();

        private readonly string IP_ADDRESS1 = "192.168.100.151";
        private readonly int IP_PORT1 = 8811;

        private byte[] dataReceived = new byte[1441];
        private bool isReceiving = false;

        public readonly float NSCALE = 1;//3000/0.38f;
        private int m_averageCount = 100;
        private ADDataSet m_aveDataSet;
        private int ignoreNum = 2;
        private long timeStamp = 0;

        AutoResetEvent blockSig = new AutoResetEvent(false);
        public void SendCommand(CMD cmdIndex, int gain = 0)
        {
            byte[] cmd = new byte[100];
            cmd[0] = 0x56;
            cmd[1] = 0xab;
            if (cmdIndex == CMD.START)
                cmd[2] = 0x01;
            else if (cmdIndex == CMD.STOP)
                cmd[2] = 0x02;
            else if (cmdIndex == CMD.GAIN)
            {
                cmd[2] = 0x03;
                for (int i = 3; i < 27; i++)
                {
                    cmd[i] = (byte)(0xf0 + gain);
                }
            }
            udpManager1.SendData(cmd, 100);
        }
        public CommMgmt(int average = 100)
        {
            m_averageCount = average;
        }
        public bool Connect()
        {
            timeStamp = 0;
            ignoreNum = 2;
            bufferCnt = 0;
            udpManager1.Connect(IP_ADDRESS1, IP_PORT1);
            SendCommand(CMD.GAIN, 0);
            //blockSig.WaitOne(3000);
            Thread.Sleep(50);
            SendCommand(CMD.START);
            //blockSig.WaitOne(3000);
            Thread.Sleep(100);
            StartReceive();
            return true;
        }

        public bool Disconnect()
        {
            StopReceive();
            SendCommand(CMD.STOP);

            udpManager1.Disconnect();

            ClearData();
            return true;
        }
        public bool StartReceive()
        {
            if (isReceiving)
                return false;

            isReceiving = true;
            Thread threadReceive = new Thread(new ThreadStart(DataReceive));
            threadReceive.Priority = ThreadPriority.Highest;
            threadReceive.Start();
            return true;
        }
        public void StopReceive()
        {
            isReceiving = false;
        }
        private void DataReceive()
        {
            while (isReceiving)
            {
                if (!ReadData())
                    Thread.Sleep(100);
            }
            isReceiving = false;
        }
        private bool ReadData()
        {
            int dataNum = 0;
            Array.Clear(dataReceived, 0, dataReceived.Length);
            //板卡1
            if (!udpManager1.ReadData(ref dataReceived, ref dataNum))
                return false;
            else
            {
                if (dataNum == 1441)
                    GetAD(ref dataReceived);
                else if (dataNum == 100)
                {
                    CMD_RES cmdRes = GetCmdRes(ref dataReceived);
                    if (cmdRes == CMD_RES.GAIN_OK)
                        blockSig.Set();
                    if (cmdRes == CMD_RES.START_OK)
                        blockSig.Set();
                    //通知发送状态
                }
                else
                    return false;
            }
            return true;
        }
        private float GetVoltage(ref byte[] data, int startIndex)
        {
            //解析电压格式 :-5v~5v
            int temp = data[startIndex] * 0x10000 + data[startIndex + 1] * 0x100 + data[startIndex + 2];
            if (temp > 0x7FFFFF)
            {
                temp -= 0x1000000;
            }
            float voltage = temp / (1677721.6f);
            return voltage;
        }
        
        private ADDataSet[] bufferSet = new ADDataSet[1000];
        private long bufferCnt = 0;
        private void GetAD(ref byte[] data)
        {
            for (int i = 0; i < 20; i++)
            {
                float[] tmpArray = new float[24];
                for (int j = 0; j < 24; j++)
                {
                    tmpArray[j] = GetVoltage(ref data, i * 72 + j * 3);
                }
                float tmpBatteryVolt = data[1440] * 40.0f;
                if (ignoreNum > 0)
                {
                    ignoreNum--;
                    return;
                }
                bufferSet[bufferCnt] = new ADDataSet(0, tmpArray, tmpBatteryVolt);
                bufferCnt++;
                if (bufferCnt == m_averageCount)
                {
                    //算平均值并导出
                    ADDataSet aveData = CalcAve();
                    bufferCnt = 0;
                    m_aveDataSet = aveData;
                }
            }
        }
        private CMD_RES GetCmdRes(ref byte[] data)
        {
            if (data[1] == 0x00)
            {
                if (data[2] == 0x02) return CMD_RES.START_FAIL;
                if (data[2] == 0x02) return CMD_RES.STOP_FAIL;
                if (data[2] == 0x03) return CMD_RES.GAIN_FAIL;
            }
            else
            {
                if (data[2] == 0x02) return CMD_RES.START_OK;
                if (data[2] == 0x02) return CMD_RES.STOP_OK;
                if (data[2] == 0x03) return CMD_RES.GAIN_OK;
            }
            return CMD_RES.EXCEPTION;
        }

        public bool GetAverageData(ref ADDataSet voltDataSet)
        {
            voltDataSet = m_aveDataSet;
            if (voltDataSet.voltageArray != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        private DataConverter m_dataConverter = new DataConverter();

        public void convertData(ref ADDataSet adDataset)
        {
            adDataset.batteryVolt = m_dataConverter.ConvertToPercnt(adDataset.batteryVolt);
        }
        public void ClearData()
        {

        }
        private ADDataSet CalcAve()
        {
            float[] tmpArray = new float[24];
            float tmpBattery = 0.0f;
            for (int i = 0; i < m_averageCount; i++)
            {
                for (int j = 0; j < 24; j++)
                {
                    tmpArray[j] += bufferSet[i].voltageArray[j];
                }
                tmpBattery += bufferSet[i].batteryVolt;
            }
            for (int j = 0; j < 24; j++)
            {
                tmpArray[j] = tmpArray[j] / m_averageCount;
            }
            tmpBattery = tmpBattery / m_averageCount;
            timeStamp++;
            return new ADDataSet(timeStamp, tmpArray, tmpBattery);
        }
    }
}


